home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / OptimizedMesh / optimizedmesh.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  32KB  |  879 lines

  1. //-----------------------------------------------------------------------------
  2. // File: OptimizedMesh.cpp
  3. //
  4. // Desc: Sample of optimizing meshes in D3D
  5. //
  6. // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <tchar.h>
  10. #include <stdio.h>
  11. #include <windows.h>
  12. #include <commdlg.h>
  13. #include <d3dx8.h>
  14. #include "D3DApp.h"
  15. #include "D3DFont.h"
  16. #include "D3DUtil.h"
  17. #include "DXUtil.h"
  18. #include "resource.h"
  19.  
  20. struct SStripData
  21. {
  22.     LPDIRECT3DINDEXBUFFER8  m_pStrips;              // strip indices (single strip)
  23.     LPDIRECT3DINDEXBUFFER8  m_pStripsMany;          // strip indices (many strips)
  24.  
  25.     DWORD                   m_cStripIndices;
  26.     DWORD                  *m_rgcStripLengths;   
  27.     DWORD                   m_cStrips;         
  28.  
  29.     SStripData()
  30.         :m_pStrips(NULL),
  31.          m_pStripsMany(NULL),
  32.          m_cStripIndices(0),
  33.          m_rgcStripLengths(NULL)
  34.     {}
  35. };
  36.  
  37. struct SMeshData
  38. {
  39.     LPD3DXMESH              m_pMeshSysMem;          // System memory copy of mesh
  40.  
  41.     LPD3DXMESH              m_pMesh;           // Local version of mesh, copied on resize
  42.     LPDIRECT3DVERTEXBUFFER8 m_pVertexBuffer;        // vertex buffer of mesh
  43.  
  44.     SStripData             *m_rgStripData;          // strip indices split by attribute
  45.     DWORD                   m_cStripDatas;
  46.  
  47.     SMeshData()
  48.         :m_pMeshSysMem(NULL),
  49.          m_pMesh(NULL),
  50.          m_pVertexBuffer(NULL),
  51.          m_rgStripData(NULL),
  52.          m_cStripDatas(0)
  53.     {}
  54.  
  55.     void ReleaseLocalMeshes()
  56.     {
  57.         SAFE_RELEASE(m_pMesh);
  58.         SAFE_RELEASE(m_pVertexBuffer);
  59.     }
  60.  
  61.     void ReleaseAll()
  62.     {
  63.         SAFE_RELEASE(m_pMeshSysMem);
  64.         SAFE_RELEASE(m_pMesh);
  65.         SAFE_RELEASE(m_pVertexBuffer);
  66.  
  67.         for (DWORD iStripData = 0; iStripData < m_cStripDatas; iStripData++)
  68.         {
  69.             SAFE_RELEASE(m_rgStripData[iStripData].m_pStrips);
  70.             SAFE_RELEASE(m_rgStripData[iStripData].m_pStripsMany);
  71.             delete []m_rgStripData[iStripData].m_rgcStripLengths;
  72.         }
  73.  
  74.         delete []m_rgStripData;
  75.         m_rgStripData = NULL;
  76.         m_cStripDatas = 0;
  77.     }
  78. };
  79.  
  80. //-----------------------------------------------------------------------------
  81. // Name: class CMyD3DApplication
  82. // Desc: Main class to run this application. Most functionality is inherited
  83. //       from the CD3DApplication base class.
  84. //-----------------------------------------------------------------------------
  85. class CMyD3DApplication : public CD3DApplication
  86. {
  87.     TCHAR               m_strMeshFilename[512];
  88.     TCHAR               m_strInitialDir[512];
  89.     
  90.     BOOL                m_bShowVertexCacheOptimized; 
  91.     BOOL                m_bShowStripReordered; 
  92.     BOOL                m_bShowStrips;        
  93.     BOOL                m_bShowSingleStrip;
  94.     BOOL                m_bForce32ByteFVF;
  95.  
  96.     CD3DFont*           m_pFont;              // Font for outputting frame stats
  97.  
  98.     CD3DArcBall         m_ArcBall;            // Mouse rotation utility
  99.     D3DXVECTOR3         m_vObjectCenter;      // Center of bounding sphere of object
  100.     FLOAT               m_fObjectRadius;      // Radius of bounding sphere of object
  101.  
  102.     D3DXMATRIX          m_matWorld;
  103.     DWORD               m_cObjectsPerSide;    // sqrt of the number of objects to draw
  104.  
  105.     DWORD               m_dwMemoryOptions;
  106.  
  107.     // various forms of mesh data
  108.     SMeshData           m_MeshAttrSorted;
  109.     SMeshData           m_MeshStripReordered;
  110.     SMeshData           m_MeshVertexCacheOptimized;
  111.  
  112.     DWORD               m_dwNumMaterials;     // Number of materials
  113.     LPDIRECT3DTEXTURE8* m_pMeshTextures;
  114.     D3DMATERIAL8*       m_pMeshMaterials;
  115.  
  116. public:
  117.     HRESULT OneTimeSceneInit();
  118.     HRESULT InitDeviceObjects();
  119.     HRESULT RestoreDeviceObjects();
  120.     HRESULT InvalidateDeviceObjects();
  121.     HRESULT DeleteDeviceObjects();
  122.     HRESULT Render();
  123.     HRESULT FrameMove();
  124.     HRESULT FinalCleanup();
  125.  
  126.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  127.     CMyD3DApplication();
  128.  
  129.     HRESULT LoadMeshData(LPD3DXMESH *pMeshSysMemLoaded, LPD3DXBUFFER *ppAdjacencyBuffer);
  130.     HRESULT OptimizeMeshData(LPD3DXMESH pMeshSysMem, LPD3DXBUFFER pAdjacencyBuffer, DWORD dwOptFlags, SMeshData *pMeshData);
  131.     HRESULT UpdateLocalMeshes(SMeshData *pMeshData);   
  132.     HRESULT DrawMeshData(SMeshData *pMeshData);
  133. };
  134.  
  135.  
  136.  
  137.  
  138. //-----------------------------------------------------------------------------
  139. // Name: WinMain()
  140. // Desc: Entry point to the program. Initializes everything, and goes into a
  141. //       message-processing loop. Idle time is used to render the scene.
  142. //-----------------------------------------------------------------------------
  143. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  144. {
  145.     CMyD3DApplication d3dApp;
  146.  
  147.     if( FAILED( d3dApp.Create( hInst ) ) )
  148.         return 0;
  149.  
  150.     return d3dApp.Run();
  151. }
  152.  
  153.  
  154.  
  155.  
  156. //-----------------------------------------------------------------------------
  157. // Name: CMyD3DApplication()
  158. // Desc: Constructor
  159. //-----------------------------------------------------------------------------
  160. CMyD3DApplication::CMyD3DApplication()
  161. {
  162.     // Override base class members
  163.     m_strWindowTitle     = _T("OptimizedMesh: Optimizing Meshes in D3D");
  164.     m_bUseDepthBuffer    = TRUE;
  165.     m_bShowCursorWhenFullscreen = TRUE;
  166.  
  167.     // Initialize member variables
  168.     m_bShowVertexCacheOptimized = TRUE;  
  169.     m_bShowStripReordered = FALSE; 
  170.     m_bShowSingleStrip = TRUE;
  171.     m_bShowStrips = FALSE;
  172.     m_bShowSingleStrip = FALSE;
  173.     m_bForce32ByteFVF = TRUE;
  174.  
  175.     m_dwMemoryOptions = D3DXMESH_MANAGED;
  176.  
  177.     m_pFont              = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  178.     
  179.     _tcscpy( m_strInitialDir, DXUtil_GetDXSDKMediaPath() );
  180.     _tcscpy( m_strMeshFilename, _T("knot.x") );
  181.  
  182.     m_cObjectsPerSide = 1;
  183.  
  184.     // initialize mesh data structures
  185.     m_dwNumMaterials = 0;
  186.     m_pMeshTextures = NULL;
  187.     m_pMeshMaterials = NULL;
  188. }
  189.  
  190. //-----------------------------------------------------------------------------
  191. // Name: OneTimeSceneInit()
  192. // Desc: Called during initial app startup, this function performs all the
  193. //       permanent initialization.
  194. //-----------------------------------------------------------------------------
  195. HRESULT CMyD3DApplication::OneTimeSceneInit()
  196. {
  197.     // Set cursor to indicate that user can move the object with the mouse
  198. #ifdef _WIN64
  199.     SetClassLongPtr( m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor( NULL, IDC_SIZEALL ) );
  200. #else
  201.     SetClassLong( m_hWnd, GCL_HCURSOR, (LONG)LoadCursor( NULL, IDC_SIZEALL ) );
  202. #endif
  203.     return S_OK;
  204. }
  205.  
  206.  
  207.  
  208.  
  209. //-----------------------------------------------------------------------------
  210. // Name: FrameMove()
  211. // Desc: Called once per frame, the call is the entry point for animating
  212. //       the scene.
  213. //-----------------------------------------------------------------------------
  214. HRESULT CMyD3DApplication::FrameMove()
  215. {
  216.     // Setup viewing postion from ArcBall
  217.     D3DXMATRIX matTemp;
  218.     D3DXMatrixTranslation( &m_matWorld, -m_vObjectCenter.x,
  219.                                       -m_vObjectCenter.y,
  220.                                       -m_vObjectCenter.z );
  221.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, m_ArcBall.GetTranslationMatrix() );
  222.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, m_ArcBall.GetRotationMatrix() );
  223.  
  224.     D3DXMatrixTranslation( &matTemp, -m_fObjectRadius  * (m_cObjectsPerSide-1),//* 0.5f,
  225.                                       -m_fObjectRadius * (m_cObjectsPerSide-1),//* 0.5f,
  226.                                       0 );
  227.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, &matTemp );
  228.  
  229.     D3DXMATRIX matView;
  230.     D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0, 0,-3.7f*m_fObjectRadius * m_cObjectsPerSide),
  231.                                   &D3DXVECTOR3( 0, 0, 0 ),
  232.                                   &D3DXVECTOR3( 0, 1, 0 ) );
  233.     m_pd3dDevice->SetTransform( D3DTS_VIEW,  &matView );
  234.  
  235.     return S_OK;
  236. }
  237.  
  238. HRESULT CMyD3DApplication::DrawMeshData(SMeshData *pMeshData)
  239. {
  240.     HRESULT hr;
  241.     DWORD iCurFace;
  242.  
  243.     // Set and draw each of the materials in the mesh
  244.     for( DWORD iMaterial=0; iMaterial < m_dwNumMaterials; iMaterial++ )
  245.     {
  246.         m_pd3dDevice->SetMaterial( &m_pMeshMaterials[iMaterial] );
  247.         m_pd3dDevice->SetTexture( 0, m_pMeshTextures[iMaterial] );
  248.  
  249.         if( !m_bShowStrips && !m_bShowSingleStrip)
  250.         {
  251.             pMeshData->m_pMesh->DrawSubset( iMaterial );
  252.         }
  253.         else  // drawing strips
  254.         {
  255.             DWORD dwFVF;
  256.             DWORD cBytesPerVertex;
  257.             DWORD iStrip;
  258.  
  259.             dwFVF = pMeshData->m_pMesh->GetFVF();
  260.             cBytesPerVertex = D3DXGetFVFVertexSize(dwFVF);
  261.  
  262.             m_pd3dDevice->SetVertexShader(dwFVF);
  263.             m_pd3dDevice->SetStreamSource(0, pMeshData->m_pVertexBuffer, cBytesPerVertex);
  264.  
  265.             if(m_bShowSingleStrip)
  266.             {
  267.                 m_pd3dDevice->SetIndices(pMeshData->m_rgStripData[iMaterial].m_pStrips, 0);
  268.  
  269.                 hr = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 
  270.                                              0, pMeshData->m_pMesh->GetNumVertices(),
  271.                                              0, pMeshData->m_rgStripData[iMaterial].m_cStripIndices - 2);
  272.                 if (FAILED(hr))
  273.                     return hr;
  274.             }
  275.             else
  276.             {
  277.                 m_pd3dDevice->SetIndices(pMeshData->m_rgStripData[iMaterial].m_pStripsMany, 0);
  278.  
  279.                 iCurFace = 0;
  280.                 for (iStrip = 0; iStrip < pMeshData->m_rgStripData[iMaterial].m_cStrips; iStrip++)
  281.                 {
  282.                     hr = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 
  283.                                                  0, pMeshData->m_pMesh->GetNumVertices(),
  284.                                                  iCurFace, pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths[iStrip]);
  285.                     if (FAILED(hr))
  286.                         return hr;
  287.                 iCurFace += 2 + pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths[iStrip];
  288.                 }
  289.             }
  290.         }
  291.     }
  292.  
  293.     return S_OK;
  294. }
  295.  
  296.  
  297. //-----------------------------------------------------------------------------
  298. // Name: Render()
  299. // Desc: Called once per frame, the call is the entry point for 3d
  300. //       rendering. This function sets up render states, clears the
  301. //       viewport, and renders the scene.
  302. //-----------------------------------------------------------------------------
  303. HRESULT CMyD3DApplication::Render()
  304. {
  305.     DWORD xOffset;
  306.     DWORD yOffset;
  307.     D3DXMATRIX matWorld;
  308.     D3DXMATRIX matTemp;
  309.     DWORD cTriangles = 0;
  310.     FLOAT fTrisPerSec;
  311.     TCHAR strInfo[120];
  312.     TCHAR *szOptString;
  313.  
  314.     // Clear the scene
  315.     m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  316.                          0x000000ff, 1.0f, 0x00000000 );
  317.  
  318.     // Draw scene
  319.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  320.     {
  321.         for (xOffset = 0; xOffset < m_cObjectsPerSide; xOffset++)
  322.         {
  323.             for (yOffset = 0; yOffset < m_cObjectsPerSide; yOffset++)
  324.             {
  325.                 D3DXMatrixTranslation( &matTemp, m_fObjectRadius * xOffset * 2,
  326.                                                   m_fObjectRadius * yOffset * 2,
  327.                                                   0 );
  328.                 D3DXMatrixMultiply( &matWorld, &m_matWorld, &matTemp );
  329.                 m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  330.  
  331.                 if (m_bShowVertexCacheOptimized)
  332.                     DrawMeshData(&m_MeshVertexCacheOptimized);
  333.                 else if (m_bShowStripReordered)
  334.                     DrawMeshData(&m_MeshStripReordered);
  335.                 else
  336.                     DrawMeshData(&m_MeshAttrSorted);
  337.             }
  338.         }
  339.  
  340.         // Calculate and show triangles per sec, a reasonable throughput number
  341.         if (m_MeshAttrSorted.m_pMesh != NULL)
  342.             cTriangles = m_MeshAttrSorted.m_pMesh->GetNumFaces() * m_cObjectsPerSide * m_cObjectsPerSide;
  343.         else
  344.             cTriangles = 0;
  345.  
  346.         fTrisPerSec = m_fFPS * cTriangles;
  347.  
  348.         if (m_bShowVertexCacheOptimized)
  349.             szOptString = _T("VCache Optimized");
  350.         else if (m_bShowStripReordered)
  351.             szOptString = _T("Strip Reordered");
  352.         else
  353.             szOptString = _T("Unoptimized");
  354.  
  355.         // Output statistics
  356.         wsprintf( strInfo, _T("%s, %ld tris per sec, %ld triangles"),
  357.                                     szOptString, (DWORD)fTrisPerSec, cTriangles);
  358.  
  359.         m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  360.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  361.         m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,0), strInfo);
  362.  
  363.  
  364.         m_pd3dDevice->EndScene();
  365.     }
  366.  
  367.     return S_OK;
  368. }
  369.  
  370.  
  371.  
  372. HRESULT CMyD3DApplication::LoadMeshData
  373.     (
  374.     LPD3DXMESH *ppMesh,
  375.     LPD3DXBUFFER *ppAdjacencyBuffer
  376.     )
  377. {
  378.     LPDIRECT3DVERTEXBUFFER8 pMeshVB   = NULL;
  379.     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
  380.     BYTE*        pVertices;
  381.     TCHAR        strMesh[512];
  382.     HRESULT      hr = S_OK;
  383.     BOOL         bNormalsInFile;
  384.     LPD3DXMESH   pMeshSysMem = NULL;
  385.     LPD3DXMESH   pMeshTemp;
  386.     DWORD        *rgdwAdjacencyTemp = NULL;
  387.     DWORD        i;
  388.     D3DXMATERIAL* d3dxMaterials;
  389.     DWORD        dw32Bit;
  390.  
  391.     // Get a path to the media file
  392.     DXUtil_FindMediaFile( strMesh, m_strMeshFilename );
  393.     
  394.     // Load the mesh from the specified file
  395.     hr = D3DXLoadMeshFromX( strMesh, D3DXMESH_SYSTEMMEM, m_pd3dDevice, 
  396.                             ppAdjacencyBuffer, &pD3DXMtrlBuffer, 
  397.                             &m_dwNumMaterials, &pMeshSysMem );
  398.     if( FAILED(hr) )
  399.         goto End;
  400.  
  401.     // remember if the mesh is 32 or 16 bit, to be added in on the clones
  402.     dw32Bit = pMeshSysMem->GetOptions() & D3DXMESH_32BIT;
  403.  
  404.     // Get the array of materials out of the returned buffer, and allocate a texture array
  405.     d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
  406.     m_pMeshMaterials = new D3DMATERIAL8[m_dwNumMaterials];
  407.     m_pMeshTextures  = new LPDIRECT3DTEXTURE8[m_dwNumMaterials];
  408.  
  409.     for( i=0; i<m_dwNumMaterials; i++ )
  410.     {
  411.         m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
  412.         m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse;
  413.         m_pMeshTextures[i]  = NULL;
  414.  
  415.         // Get a path to the texture
  416.         TCHAR strPath[512];
  417.         if (d3dxMaterials[i].pTextureFilename != NULL)
  418.         {
  419.             DXUtil_FindMediaFile( strPath, d3dxMaterials[i].pTextureFilename );
  420.  
  421.             // Load the texture
  422.             D3DXCreateTextureFromFile( m_pd3dDevice, strPath, &m_pMeshTextures[i] );
  423.         }
  424.     }
  425.  
  426.     // Done with the material buffer
  427.     SAFE_RELEASE( pD3DXMtrlBuffer );
  428.  
  429.     // Lock the vertex buffer, to generate a simple bounding sphere
  430.     hr = pMeshSysMem->GetVertexBuffer( &pMeshVB );
  431.     if( SUCCEEDED(hr) )
  432.     {
  433.         hr = pMeshVB->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK );
  434.         if( SUCCEEDED(hr) )
  435.         {
  436.             hr = D3DXComputeBoundingSphere( pVertices, pMeshSysMem->GetNumVertices(),
  437.                                             pMeshSysMem->GetFVF(),
  438.                                             &m_vObjectCenter, &m_fObjectRadius );
  439.             pMeshVB->Unlock();
  440.         }
  441.         pMeshVB->Release();
  442.     }
  443.     if( FAILED(hr) )
  444.         goto End;
  445.  
  446.     // remember if there were normals in the file, before possible clone operation
  447.     bNormalsInFile = pMeshSysMem->GetFVF() & D3DFVF_NORMAL;
  448.  
  449.     // if using 32byte vertices, check fvf
  450.     if (m_bForce32ByteFVF)
  451.     {
  452.         // force 32 byte vertices
  453.         if (pMeshSysMem->GetFVF() != (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1))
  454.         {
  455.             hr = pMeshSysMem->CloneMeshFVF( pMeshSysMem->GetOptions(), D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1, 
  456.                                               m_pd3dDevice, &pMeshTemp );
  457.             if( FAILED(hr) )
  458.                 goto End;
  459.  
  460.             pMeshSysMem->Release();
  461.             pMeshSysMem = pMeshTemp;
  462.         }
  463.     }
  464.     // otherwise, just make sure that there is a normal mesh
  465.     else if ( !(pMeshSysMem->GetFVF() & D3DFVF_NORMAL) )
  466.     {
  467.         hr = pMeshSysMem->CloneMeshFVF( pMeshSysMem->GetOptions(), pMeshSysMem->GetFVF() | D3DFVF_NORMAL, 
  468.                                             m_pd3dDevice, &pMeshTemp );
  469.         if (FAILED(hr))
  470.             return hr;
  471.  
  472.         pMeshSysMem->Release();
  473.         pMeshSysMem = pMeshTemp;
  474.     }
  475.  
  476.  
  477.     // Compute normals for the mesh, if not present
  478.     if (!bNormalsInFile)
  479.     {
  480.         D3DXComputeNormals( pMeshSysMem, NULL );
  481.     }
  482.  
  483.     *ppMesh = pMeshSysMem;
  484.     pMeshSysMem = NULL;
  485.  
  486. End:
  487.     SAFE_RELEASE( pMeshSysMem );
  488.    
  489.     return hr;
  490. }
  491.  
  492. HRESULT CMyD3DApplication::OptimizeMeshData
  493.     (
  494.     LPD3DXMESH pMeshSysMem,
  495.     LPD3DXBUFFER pAdjacencyBuffer,
  496.     DWORD dwOptFlags, 
  497.     SMeshData *pMeshData
  498.     )
  499. {
  500.     HRESULT      hr = S_OK;
  501.     LPD3DXBUFFER pbufTemp = NULL;
  502.     DWORD iMaterial;
  503.  
  504.     // attribute sort - the un-optimized mesh option
  505.     //          remember the adjacency for the vertex cache optimization
  506.     hr = pMeshSysMem->Optimize( dwOptFlags|D3DXMESH_SYSTEMMEM,
  507.                                  (DWORD*)pAdjacencyBuffer->GetBufferPointer(),
  508.                                  NULL, NULL, NULL, &pMeshData->m_pMeshSysMem);
  509.     if( FAILED(hr) )
  510.         goto End;
  511.  
  512.     pMeshData->m_cStripDatas = m_dwNumMaterials;
  513.     pMeshData->m_rgStripData = new SStripData[pMeshData->m_cStripDatas];
  514.     if (pMeshData->m_rgStripData == NULL)
  515.     {
  516.         hr = E_OUTOFMEMORY;
  517.         goto End;
  518.     }
  519.  
  520.     for (iMaterial = 0; iMaterial < m_dwNumMaterials; iMaterial++)
  521.     {
  522.         hr = D3DXConvertMeshSubsetToSingleStrip(pMeshData->m_pMeshSysMem, iMaterial, 
  523.                                 D3DXMESH_IB_MANAGED, &pMeshData->m_rgStripData[iMaterial].m_pStrips, 
  524.                                 &pMeshData->m_rgStripData[iMaterial].m_cStripIndices);
  525.         if (FAILED(hr))
  526.             goto End;
  527.  
  528.         hr = D3DXConvertMeshSubsetToStrips(pMeshData->m_pMeshSysMem, iMaterial, 
  529.                                 D3DXMESH_IB_MANAGED, &pMeshData->m_rgStripData[iMaterial].m_pStripsMany, 
  530.                                 NULL, &pbufTemp, &pMeshData->m_rgStripData[iMaterial].m_cStrips);
  531.         if (FAILED(hr))
  532.             goto End;
  533.  
  534.         pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths = new DWORD[pMeshData->m_rgStripData[iMaterial].m_cStrips];
  535.         if (pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths == NULL)
  536.         {
  537.             hr = E_OUTOFMEMORY;
  538.             goto End;
  539.         }
  540.         memcpy(pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths, pbufTemp->GetBufferPointer(), sizeof(DWORD)*pMeshData->m_rgStripData[iMaterial].m_cStrips);
  541.  
  542.     }
  543.  
  544. End:
  545.     SAFE_RELEASE(pbufTemp);
  546.  
  547.     return hr;
  548. }
  549.  
  550. //-----------------------------------------------------------------------------
  551. // Name: InitDeviceObjects()
  552. // Desc: Initialize scene objects.
  553. //-----------------------------------------------------------------------------
  554. HRESULT CMyD3DApplication::InitDeviceObjects()
  555. {
  556.     HRESULT      hr = S_OK;
  557.     LPD3DXMESH   pMeshSysMem = NULL;
  558.     LPD3DXBUFFER pAdjacencyBuffer = NULL;
  559.  
  560.     // Initialize the font 
  561.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  562.  
  563.     // check current display setting
  564.     CheckMenuItem( GetMenu(m_hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_CHECKED );
  565.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWNONOPTIMIZEDMESH, (!m_bShowStripReordered && !m_bShowVertexCacheOptimized) ? MF_CHECKED : MF_UNCHECKED  );
  566.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWVCACHEOPTIMIZED, m_bShowVertexCacheOptimized ? MF_CHECKED : MF_UNCHECKED );
  567.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWSTRIPREORDERED, m_bShowStripReordered ? MF_CHECKED : MF_UNCHECKED );
  568.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWTRILIST, (!m_bShowStrips && !m_bShowSingleStrip) ? MF_CHECKED : MF_UNCHECKED );
  569.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWONESTRIP, m_bShowSingleStrip ? MF_CHECKED : MF_UNCHECKED );
  570.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWMANYSTRIPS, m_bShowStrips ? MF_CHECKED : MF_UNCHECKED );
  571.  
  572.     CheckMenuItem( GetMenu(m_hWnd), IDM_DYNAMICVB, (m_dwMemoryOptions == D3DXMESH_DYNAMIC) ? MF_CHECKED : MF_UNCHECKED );
  573.     CheckMenuItem( GetMenu(m_hWnd), IDM_FORCE32BYTEVERTEX, m_bForce32ByteFVF ? MF_CHECKED : MF_UNCHECKED );
  574.  
  575.     hr = LoadMeshData(&pMeshSysMem, &pAdjacencyBuffer);
  576.     if (FAILED(hr))
  577.     {
  578.         // ignore load errors, just draw blank screen if mesh is invalid
  579.         hr = S_OK;
  580.         goto End;
  581.     }
  582.  
  583.     hr = OptimizeMeshData(pMeshSysMem, pAdjacencyBuffer, D3DXMESHOPT_ATTRSORT, &m_MeshAttrSorted);
  584.     if (FAILED(hr))
  585.         goto End;
  586.  
  587.     hr = OptimizeMeshData(pMeshSysMem, pAdjacencyBuffer, D3DXMESHOPT_STRIPREORDER, &m_MeshStripReordered);
  588.     if (FAILED(hr))
  589.         goto End;
  590.  
  591.     hr = OptimizeMeshData(pMeshSysMem, pAdjacencyBuffer, D3DXMESHOPT_VERTEXCACHE, &m_MeshVertexCacheOptimized);
  592.     if (FAILED(hr))
  593.         goto End;
  594.  
  595. End:
  596.     SAFE_RELEASE( pMeshSysMem );
  597.     SAFE_RELEASE( pAdjacencyBuffer );
  598.    
  599.     return hr;
  600. }
  601.  
  602. HRESULT CMyD3DApplication::UpdateLocalMeshes(SMeshData *pMeshData)
  603. {
  604.     HRESULT hr = S_OK;
  605.  
  606.     // if a mesh was loaded, update the local meshes
  607.     if (pMeshData->m_pMeshSysMem != NULL) 
  608.     {
  609.         hr = pMeshData->m_pMeshSysMem->CloneMeshFVF( m_dwMemoryOptions|D3DXMESH_VB_WRITEONLY, pMeshData->m_pMeshSysMem->GetFVF(),
  610.                                           m_pd3dDevice, &pMeshData->m_pMesh );
  611.         if (FAILED(hr))
  612.             goto End;
  613.  
  614.         hr = pMeshData->m_pMesh->GetVertexBuffer(&pMeshData->m_pVertexBuffer);
  615.         if (FAILED(hr))
  616.             goto End;
  617.  
  618.     }
  619.  
  620. End:
  621.     return hr;
  622. }
  623.  
  624. //-----------------------------------------------------------------------------
  625. // Name: RestoreDeviceObjects()
  626. // Desc: Initialize scene objects.
  627. //-----------------------------------------------------------------------------
  628. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  629. {
  630.     m_pFont->RestoreDeviceObjects();
  631.  
  632.     // Setup render state
  633.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,     TRUE );
  634.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  635.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  636.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  637.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  638.  
  639.     // Setup the light
  640.     D3DLIGHT8 light;
  641.     light.Type         = D3DLIGHT_DIRECTIONAL;
  642.     light.Diffuse.r    = light.Diffuse.g  = light.Diffuse.b  = 1.0f;
  643.     light.Specular.r   = light.Specular.g = light.Specular.b = 0.0f;
  644.     light.Ambient.r    = light.Ambient.g  = light.Ambient.b  = 0.3f;
  645.     light.Position     = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  646.     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &D3DXVECTOR3( 0.3f, -1.0f, 1.0f ) );
  647.     light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
  648.     light.Range        = sqrtf(FLT_MAX);
  649.     m_pd3dDevice->SetLight(0, &light );
  650.     m_pd3dDevice->LightEnable(0, TRUE );
  651.  
  652.     m_ArcBall.SetWindow( m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, 0.85f );
  653.     m_ArcBall.SetRadius( m_fObjectRadius );
  654.  
  655.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  656.  
  657.     D3DXMATRIX matProj;
  658.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, m_fObjectRadius/64.0f,
  659.                                 m_fObjectRadius*200.0f);
  660.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  661.  
  662.     // update the local copies of the meshes
  663.     UpdateLocalMeshes(&m_MeshAttrSorted);
  664.     UpdateLocalMeshes(&m_MeshStripReordered);
  665.     UpdateLocalMeshes(&m_MeshVertexCacheOptimized);
  666.  
  667.     return S_OK;
  668. }
  669.  
  670.  
  671.  
  672.  
  673. //-----------------------------------------------------------------------------
  674. // Name: InvalidateDeviceObjects()
  675. // Desc: 
  676. //-----------------------------------------------------------------------------
  677. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  678. {
  679.     m_pFont->InvalidateDeviceObjects();
  680.  
  681.     m_MeshAttrSorted.ReleaseLocalMeshes();
  682.     m_MeshStripReordered.ReleaseLocalMeshes();
  683.     m_MeshVertexCacheOptimized.ReleaseLocalMeshes();
  684.  
  685.     return S_OK;
  686. }
  687.  
  688.  
  689.  
  690.  
  691. //-----------------------------------------------------------------------------
  692. // Name: DeleteDeviceObjects()
  693. // Desc: Called when the app is exiting, or the device is being changed,
  694. //       this function deletes any device dependent objects.
  695. //-----------------------------------------------------------------------------
  696. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  697. {
  698.     m_pFont->DeleteDeviceObjects();
  699.  
  700.     for( UINT i=0; i<m_dwNumMaterials; i++ )
  701.         SAFE_RELEASE( m_pMeshTextures[i] );
  702.     SAFE_DELETE_ARRAY( m_pMeshTextures );
  703.     SAFE_DELETE_ARRAY( m_pMeshMaterials );
  704.  
  705.     m_MeshAttrSorted.ReleaseAll();
  706.     m_MeshStripReordered.ReleaseAll();
  707.     m_MeshVertexCacheOptimized.ReleaseAll();
  708.  
  709.     m_dwNumMaterials = 0;
  710.  
  711.     return S_OK;
  712. }
  713.  
  714.  
  715.  
  716.  
  717. //-----------------------------------------------------------------------------
  718. // Name: FinalCleanup()
  719. // Desc: Called during initial app startup, this function performs all the
  720. //       permanent initialization.
  721. //-----------------------------------------------------------------------------
  722. HRESULT CMyD3DApplication::FinalCleanup()
  723. {
  724.     SAFE_DELETE( m_pFont );
  725.  
  726.     return S_OK;
  727. }
  728.  
  729.  
  730.  
  731.  
  732. //-----------------------------------------------------------------------------
  733. // Name: MsgProc()
  734. // Desc: Message proc function to handle key and menu input
  735. //-----------------------------------------------------------------------------
  736. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  737.                                     LPARAM lParam )
  738. {
  739.     // Pass mouse messages to the ArcBall so it can build internal matrices
  740.     m_ArcBall.HandleMouseMessages( hWnd, uMsg, wParam, lParam );
  741.  
  742.     // Trap the context menu
  743.     if( WM_CONTEXTMENU==uMsg )
  744.         return 0;
  745.  
  746.     if( uMsg == WM_COMMAND )
  747.     {
  748.         // Toggle mesh optimization
  749.         if( LOWORD(wParam) == IDM_SHOWNONOPTIMIZEDMESH )
  750.         {
  751.             m_bShowVertexCacheOptimized = FALSE;
  752.             m_bShowStripReordered = FALSE;
  753.  
  754.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWNONOPTIMIZEDMESH, MF_CHECKED );
  755.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWVCACHEOPTIMIZED, MF_UNCHECKED );
  756.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWSTRIPREORDERED, MF_UNCHECKED );
  757.         }
  758.         else if( LOWORD(wParam) == IDM_SHOWVCACHEOPTIMIZED )
  759.         {
  760.             m_bShowVertexCacheOptimized = TRUE;
  761.             m_bShowStripReordered = FALSE;
  762.  
  763.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWNONOPTIMIZEDMESH, MF_UNCHECKED );
  764.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWVCACHEOPTIMIZED, MF_CHECKED );
  765.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWSTRIPREORDERED, MF_UNCHECKED );
  766.         }
  767.         else if( LOWORD(wParam) == IDM_SHOWSTRIPREORDERED )
  768.         {
  769.             m_bShowVertexCacheOptimized = FALSE;
  770.             m_bShowStripReordered = TRUE;
  771.  
  772.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWNONOPTIMIZEDMESH, MF_UNCHECKED );
  773.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWVCACHEOPTIMIZED, MF_UNCHECKED );
  774.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWSTRIPREORDERED, MF_CHECKED );
  775.         }
  776.         // Toggle strips
  777.         else if( LOWORD(wParam) == IDM_SHOWTRILIST )
  778.         {
  779.             m_bShowStrips = FALSE;
  780.             m_bShowSingleStrip = FALSE;
  781.  
  782.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWTRILIST, MF_CHECKED );
  783.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWONESTRIP, MF_UNCHECKED );
  784.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWMANYSTRIPS, MF_UNCHECKED );
  785.         }
  786.         else if( LOWORD(wParam) == IDM_SHOWONESTRIP )
  787.         {
  788.             m_bShowStrips = FALSE;
  789.             m_bShowSingleStrip = TRUE;
  790.  
  791.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWTRILIST, MF_UNCHECKED );
  792.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWONESTRIP, MF_CHECKED );
  793.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWMANYSTRIPS, MF_UNCHECKED );
  794.         }
  795.         else if( LOWORD(wParam) == IDM_SHOWMANYSTRIPS )
  796.         {
  797.             m_bShowStrips = TRUE;
  798.             m_bShowSingleStrip = FALSE;
  799.  
  800.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWTRILIST, MF_UNCHECKED );
  801.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWONESTRIP, MF_UNCHECKED );
  802.             CheckMenuItem( GetMenu(hWnd), IDM_SHOWMANYSTRIPS, MF_CHECKED );
  803.         }
  804.         // Toggle vertex buffer mode
  805.         else if( LOWORD(wParam) == IDM_DYNAMICVB )
  806.         {
  807.             if (m_dwMemoryOptions == D3DXMESH_DYNAMIC)
  808.             {
  809.                 m_dwMemoryOptions = D3DXMESH_MANAGED;
  810.                 CheckMenuItem( GetMenu(hWnd), IDM_DYNAMICVB, MF_UNCHECKED );
  811.             }
  812.             else
  813.             {
  814.                 m_dwMemoryOptions = D3DXMESH_DYNAMIC;
  815.                 CheckMenuItem( GetMenu(hWnd), IDM_DYNAMICVB, MF_CHECKED );
  816.             }
  817.             // Destroy and recreate everything
  818.             InvalidateDeviceObjects();
  819.             RestoreDeviceObjects();
  820.         }        
  821.         else if( LOWORD(wParam) == IDM_FORCE32BYTEVERTEX )
  822.         {
  823.             m_bForce32ByteFVF = !m_bForce32ByteFVF;
  824.  
  825.             CheckMenuItem( GetMenu(hWnd), IDM_FORCE32BYTEVERTEX, m_bForce32ByteFVF ? MF_CHECKED : MF_UNCHECKED );
  826.  
  827.             // Destroy and recreate everything
  828.             InvalidateDeviceObjects();
  829.             DeleteDeviceObjects();
  830.             InitDeviceObjects();
  831.             RestoreDeviceObjects();
  832.         }
  833.         // Handle the open file command
  834.         else if( LOWORD(wParam) == IDM_OPENFILE )
  835.         {
  836.             TCHAR g_strFilename[512]   = _T("");
  837.  
  838.             // Display the OpenFileName dialog. Then, try to load the specified file
  839.             OPENFILENAME ofn = { sizeof(OPENFILENAME), NULL, NULL,
  840.                                 _T(".X Files (.x)\0*.x\0\0"), 
  841.                                 NULL, 0, 1, m_strMeshFilename, 512, g_strFilename, 512, 
  842.                                 m_strInitialDir, _T("Open Mesh File"), 
  843.                                 OFN_FILEMUSTEXIST, 0, 1, NULL, 0, NULL, NULL };
  844.  
  845.             if( TRUE == GetOpenFileName( &ofn ) )
  846.             {
  847.                 _tcscpy( m_strInitialDir, m_strMeshFilename );
  848.                 TCHAR* pLastSlash =  _tcsrchr( m_strInitialDir, _T('\\') );
  849.                 if( pLastSlash )
  850.                     *pLastSlash = 0;
  851.                 SetCurrentDirectory( m_strInitialDir );
  852.  
  853.                 // Destroy and recreate everything
  854.                 InvalidateDeviceObjects();
  855.                 DeleteDeviceObjects();
  856.                 InitDeviceObjects();
  857.                 RestoreDeviceObjects();
  858.             }
  859.         }
  860.  
  861.         else if ((LOWORD(wParam) >= ID_OPTIONS_DISPLAY1) && (LOWORD(wParam) <= ID_OPTIONS_DISPLAY36))
  862.         {
  863.             // uncheck old item
  864.             CheckMenuItem( GetMenu(hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_UNCHECKED );
  865.  
  866.             // calc new item
  867.             m_cObjectsPerSide = LOWORD(wParam) - ID_OPTIONS_DISPLAY1 + 1;
  868.  
  869.             // check new item
  870.             CheckMenuItem( GetMenu(hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_CHECKED );
  871.         }
  872.     }
  873.  
  874.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  875. }
  876.  
  877.  
  878.  
  879.